#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/fs.h>
#include <linux/signal.h>
#include <linux/mutex.h>
#include <linux/mm.h>
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
#include <linux/poll.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/moduleparam.h>

#include <linux/gpio/consumer.h> // gpiod函数所需头文件
#include <linux/platform_device.h>



static int major = 0;
static struct class *led_class;
static struct gpio_desc *led_gpio;


static int led_open(struct inode *inode, struct file *file)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	gpiod_direction_output(led_gpio, 0);
	return 0;
}

static ssize_t led_read(struct file *file, char __user *user, size_t size, loff_t *off)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}

static ssize_t led_write(struct file *file, const char __user *in, size_t size, loff_t *off)
{
	int err;
	char status;

	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	err = copy_from_user(&status, in, 1);

	// 控制GPIO
	gpiod_set_value(led_gpio, status);

	return 1;
}

static int led_release(struct inode *inode, struct file *file)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}


static struct file_operations pinctrl_fops = {
	.owner		= THIS_MODULE,
	.open		= led_open,
	.read		= led_read,
	.write		= led_write,
	.release	= led_release,
};


// 当设备和驱动匹配成功时调用，用于初始化设备
static int my_gpio_probe(struct platform_device *pdev)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	// 从设备树中解析
	led_gpio = gpiod_get(&pdev->dev, "led", 0); // "led"的意思是解析led-gpios属性下的内容

	if(IS_ERR(led_gpio))
	{
		dev_err(&pdev->dev, "Failed to get GPIO for led\n");
		return PTR_ERR(led_gpio);
	}

	// 注册file_operations
	major = register_chrdev(0, "my_pinctrl_led", &pinctrl_fops);
	led_class = class_create(THIS_MODULE, "my_pinctrl_led_class");

	if(IS_ERR(led_class))
	{
		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
		unregister_chrdev(major, "led");
		gpiod_put(led_gpio);
		return PTR_ERR(led_class);
	}

	device_create(led_class, NULL, MKDEV(major, 0), NULL, "my_pinctrl_led%d", 0);  // /dev/my_pinctrl_led0

	return 0;
}

static int my_gpio_remove(struct platform_device *pdev)
{
	device_destroy(led_class, MKDEV(major, 0));
	class_destroy(led_class);
	unregister_chrdev(major, "my_pinctrl_led");
	gpiod_put(led_gpio);

	return 0;
}

// 与设备树的compatible属性匹配的表
static const struct of_device_id my_pinctrl_gpios[] = {
	{ .compatible = "my_led,pinctrl_drv" },
	{ }, // 告诉内核这个匹配表到此为止了，不要再往后读了
};

static struct platform_driver my_gpio_driver = {
	.probe = my_gpio_probe,
	.remove = my_gpio_remove,
	.driver = {
		.name = "my_pinctrl_leds",
		.of_match_table = my_pinctrl_gpios,
	},
};


static int __init pinctrl_init(void)
{
	int err;

	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	err = platform_driver_register(&my_gpio_driver);

	return err;
}

static void __exit pinctrl_exit(void)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	platform_driver_unregister(&my_gpio_driver);
}

module_init(pinctrl_init);
module_exit(pinctrl_exit);
MODULE_LICENSE("GPL");



